home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / src / FileDialog.C < prev    next >
C/C++ Source or Header  |  1990-12-06  |  11KB  |  535 lines

  1. //$FileDialog, FileItem$
  2.  
  3. #include <stdio.h>
  4.  
  5. #include "ET++.h"
  6.  
  7. #include "FileDialog.h"
  8. #include "PopupItem.h"
  9. #include "EditTextItem.h"
  10. #include "BorderItems.h"
  11. #include "Buttons.h"
  12. #include "ScrollBar.h"
  13. #include "CheapText.h"
  14. #include "System.h"
  15. #include "CollView.h"
  16. #include "OrdColl.h"
  17. #include "Directory.h"
  18.  
  19. char *cPathSeparator= "/",
  20.      *cPathRoot     = "/";
  21.       
  22. const int cPathBuf      =   200,
  23.       cItemMinWidth =   250,
  24.       cNumItems     =   7;
  25.  
  26. const Point cIconSize(16);
  27.  
  28. //---- Path -----------------------------------------------------------------
  29.  
  30. Path::Path()
  31. {
  32.     path= 0;
  33.     Reset();
  34. }
  35.  
  36. Path::~Path()
  37. {
  38.     SafeDelete(path);
  39. }
  40.  
  41. const char *Path::GetPath()
  42. {
  43.     return path;
  44. }
  45.  
  46. void Path::Reset()
  47. {
  48.     if (gSystem)
  49.     strreplace(&path, gSystem->WorkingDirectory());
  50.     p= path;
  51. }
  52.  
  53. void Path::Start()
  54. {
  55.     p= path;
  56. }
  57.  
  58. char *Path::operator()()
  59. {  
  60.     char buf[300];
  61.      
  62.     if (*p == 0) {
  63.     p= path;
  64.     return 0;
  65.     }
  66.     p++;
  67.     char *c= buf;
  68.     while (*p && *p != '/')
  69.     *c++= *p++;
  70.     *c= '\0';
  71.     return form("%s", buf);
  72. }
  73.  
  74. int Path::Components()
  75. {
  76.     char *cp= path+1;
  77.     int n= 1;
  78.     if (*cp == 0)
  79.     return n;
  80.     while (*cp) 
  81.     if (*cp++ == '/')
  82.         n++;
  83.     return n+1;
  84. }
  85.  
  86. char *Path::At(int at)
  87. {
  88.     char buf[1000];
  89.     
  90.     int i= 0;
  91.     char *c= path+1, res= 0;
  92.     
  93.     for (; *c && i < at; c++)
  94.     if (*c == '/')
  95.         i++;
  96.     strncpy(buf, path, c - path);
  97.     buf[c - path]= '\0';
  98.     return form("%s", buf);
  99. }
  100.  
  101. //---- FileDialog --------------------------------------------------------------
  102.  
  103. MetaImpl(FileDialog, (TP(scroller), TP(eti), TP(title), TP(pathname),
  104.                     TE(flags), TP(collview), TP(fileList), 0));
  105.  
  106. FileDialog::FileDialog(char *ti) : Dialog(ti, eBWinBlock)
  107. {
  108.     title= new TextItem(ti);
  109.     doc= 0;
  110.     fileList= 0;
  111.     doctype= 0;
  112.     initDir= 0;
  113.     pathname= new char[cPathBuf];
  114. }
  115.  
  116. FileDialog::~FileDialog()
  117. {
  118.     SafeDelete(pathname);
  119.     SafeDelete(doctype);
  120.     SafeDelete(initDir);
  121. }
  122.  
  123. int FileDialog::ShowInWindow(FileDialogFlags f, Clipper *fp, EvtHandler *eh, char *p)
  124. {
  125.     flags= f;
  126.     doc= eh;
  127.  
  128.     if (p == 0) {
  129.     if (f == eFDRead)
  130.         p= "Open File Named:";
  131.     else if (f == eFDWrite)
  132.         p= "Save in File Named:";
  133.     else
  134.         p= "Import File Named:";
  135.     }
  136.     
  137.     title->SetString(p);
  138.     // check whether working directory is still correct
  139.     strreplace(&initDir, gSystem->WorkingDirectory());
  140.     if (fileList && strcmp(initDir, path.GetPath()) != 0) {
  141.     path.Reset();
  142.     UpdatePath();
  143.     UpdateList();
  144.     }
  145.     return Dialog::ShowOnWindow(fp);
  146. }
  147.  
  148. void FileDialog::UpdateList()
  149. {
  150.     Directory *dir= gSystem->MakeDirectory(".");
  151.     char *name;
  152.     VObject *vop;
  153.     int i;
  154.     
  155.     fileList= new OrdCollection;
  156.     
  157.     for (i= 0; name= (*dir)(); i++)
  158.     if (strcmp(name, ".") && (vop= MakeFileItem(name)))
  159.         fileList->Add(vop);
  160.     
  161.     fileList->Sort();
  162.  
  163.     if (collview == 0) {
  164.     collview= new CollectionView(this, fileList, eCVDontStuckToBorder);
  165.     collview->SetMinExtent(Point(cItemMinWidth, 0));
  166.     collview->SetId(cIdList);
  167.     collview->SetContainer(this);
  168.     } else
  169.     collview->SetCollection(fileList);
  170.     if (eti)
  171.     eti->SetString((byte*)"");
  172. }
  173.  
  174. VObject *FileDialog::MakeFileItem(char *name)
  175. {
  176.     return new FileItem(name);
  177. }
  178.  
  179. VObject *FileDialog::Hook(FileDialogFlags)
  180. {
  181.     return 0;
  182. }
  183.  
  184. int FileDialog::GetSaveOption()
  185. {
  186.     return 0;
  187. }
  188.  
  189. int FileDialog::ItemHeight()
  190. {
  191.     VObject *vop= (VObject*)fileList->At(0);
  192.     if (vop)
  193.     return vop->GetMinSize().extent.y;
  194.     return 16;
  195. }
  196.  
  197. VObject *FileDialog::DoCreateDialog()
  198. {
  199.     pathMenu= new Menu("", FALSE, 1, 0, FALSE);
  200.     pathMenu->SetFlag(eMenuNoScroll);
  201.     pathPopup= new PopupItem(cIdPath, path.Components(), "CWD:", pathMenu);
  202.  
  203.     UpdatePath();
  204.     UpdateList();
  205.     
  206.     VObject *actions=
  207.     new Expander(cIdNone, eHor, 20, 
  208.         new ActionButton(cIdOk, "Ok", TRUE),
  209.         new ActionButton (cIdCancel, "Cancel"),
  210.         new ActionButton(cIdUpdate, "Update"),
  211.         Hook(eFDRead),
  212.         0
  213.     );
  214.     
  215.     VObject *name=
  216.     new Expander(cIdNone, eVert, 2,
  217.         title,
  218.         new BorderItem(eti= new EditTextItem(cIdName)),
  219.         0
  220.     );
  221.     
  222.     
  223.     scroller= new Scroller(collview, Point(cItemMinWidth, ItemHeight()*cNumItems), cIdList);
  224.  
  225.     // overall layout
  226.     return
  227.     new BorderItem(
  228.         new Expander(cIdNone, eVert, 20,
  229.         pathPopup,
  230.         scroller,
  231.         name,
  232.         actions,
  233.         0
  234.         ),
  235.         20, 0
  236.     );
  237. }
  238.  
  239. void FileDialog::DoSetup()
  240. {
  241.     EnableItem(cIdOk, eti->GetTextSize() > 0);
  242.     pathPopup->Enable(path.Components() > 1, TRUE);
  243. }
  244.  
  245. Command *FileDialog::DispatchEvents(Point lp, Token t, Clipper *vf)
  246. {
  247.     if (t.IsKey() || t.IsCursorKey()) {
  248.     Command *cmd= scroller->Input(lp, t, vf);
  249.     if (cmd)
  250.         return cmd;
  251.     }
  252.     return Dialog::DispatchEvents(lp, t, vf);
  253. }
  254.  
  255. void FileDialog::Control(int id, int p, void *v)
  256. {
  257.     VObject *gop;
  258.     
  259.     switch (id) {
  260.     
  261.     case cIdUpdate:
  262.     UpdateList();
  263.     return;
  264.     
  265.     case cIdList:
  266.     switch (p) {
  267.     case cPartCollSelect:
  268.         gop= (VObject*) collview->GetCollection()->At( (int) v );
  269.         char *fname= gop->AsString();
  270.         
  271.         if (fname && strlen(fname) > 0) {
  272.         eti->SetString((byte*)gop->AsString());
  273.         eti->SetSelection();
  274.         DoSetup();
  275.         }
  276.         break;
  277.     case cPartCollDoubleSelect:
  278.         if (OpenOrChangeDir()) 
  279.         Dialog::Control(cIdOk, cPartAction, v);
  280.         break;
  281.     }
  282.     return;
  283.     
  284.     case cIdName:
  285.     if (p == cPartChangedText && v == eti)
  286.         DoSetup();
  287.     break;
  288.     
  289.     case cIdOk:
  290.     if (!OpenOrChangeDir())
  291.         return;
  292.     break;
  293.     
  294.     case cIdCancel:
  295.     gSystem->ChangeDirectory(initDir); 
  296.     break;
  297.     
  298.     case cIdPath:
  299.     eti->SetString((byte*)path.At(p-cIdComponent));
  300.     eti->SetSelection();
  301.     OpenOrChangeDir();
  302.     return;
  303.  
  304.     default:
  305.     break;
  306.     }
  307.     Dialog::Control(id, p, v);
  308. }
  309.  
  310. bool FileDialog::OpenOrChangeDir()
  311. {
  312.     Text *t;
  313.     
  314.     t= eti->GetText();
  315.     t->CopyInStr((byte*)pathname, cPathBuf, 0, t->Size());
  316.  
  317.     if (gSystem->ExpandPathName(pathname, cPathBuf-1)) {
  318.     ShowAlert(eAlertNote, "%s (%s)", gSystem->GetErrorStr(), pathname);
  319.     return FALSE;
  320.     }
  321.     SafeDelete(doctype);
  322.     doctype= gSystem->GetFileType(pathname);
  323.     if (ChangeDirectory())
  324.     return FALSE;
  325.     if (flags == eFDWrite) {
  326.     if (NotWritable(pathname))
  327.         return FALSE;
  328.     } else {
  329.     if (NotReadable(pathname))
  330.         return FALSE;
  331.     if (WrongType()) {
  332.         ShowAlert(eAlertNote, "file @B%s@P has wrong type (%s)", pathname,
  333.                               doctype->Type());
  334.         return FALSE;
  335.     }
  336.     }
  337.     return TRUE;
  338. }
  339.  
  340. bool FileDialog::NotReadable(char *name)
  341. {
  342.     if (gSystem->AccessPathName(name, 4)) {
  343.     ShowAlert(eAlertNote, "Can't open document @B%s@P for reading\n%s", name,
  344.                             gSystem->GetErrorStr());
  345.     return TRUE;
  346.     }
  347.     return FALSE;
  348. }
  349.  
  350. bool FileDialog::NotWritable(char *name)
  351. {
  352.     if (gSystem->AccessPathName(name, 0)) {
  353.     char *p= rindex(name, '/'), buf[1000];
  354.     if (!p)
  355.         strcpy(buf, ".");
  356.     else 
  357.         strncpy(buf, name, p-name);
  358.     if (gSystem->AccessPathName(buf, 2)) {
  359.         ShowAlert(eAlertNote, "Document @B%s@P is not writable\n%s", name,
  360.                             gSystem->GetErrorStr());
  361.         return TRUE;
  362.     }
  363.     return FALSE;
  364.     }
  365.     if (ShowAlert(eAlertCaution, "file @B%s@P exists\noverwrite ?", name) != cIdYes)
  366.     return TRUE;
  367.     if (gSystem->AccessPathName(name, 2)) {
  368.     ShowAlert(eAlertNote, "Document @B%s@P is not writable\n%s", name,
  369.                             gSystem->GetErrorStr());
  370.     return TRUE;
  371.     }
  372.     return FALSE;
  373. }
  374.  
  375. bool FileDialog::WrongType()
  376. {
  377.     if (doc) {
  378.     if (doc->IsKindOf(Document)) {
  379.         if (flags == eFDImport)
  380.         return ! ((Document*)doc)->CanImportDocument(doctype);
  381.         if (((Document*)doc)->CanLoadDocument(doctype))
  382.         return FALSE;
  383.     }
  384.     return ! gApplication->CanOpenDocument(doctype);
  385.     }
  386.     return TRUE;
  387. }
  388.  
  389. bool FileDialog::ChangeDirectory()
  390. {
  391.     if (strcmp(doctype->Type(), cDocTypeDirectory) == 0) {
  392.     if (!gSystem->ChangeDirectory(pathname))
  393.         ShowAlert(eAlertNote, "Cannot change directory to @B%s@P", pathname);
  394.     else {
  395.         path.Reset();
  396.         UpdatePath();
  397.         UpdateList();
  398.     } 
  399.     return TRUE;
  400.     }
  401.     return FALSE;
  402. }
  403.  
  404. void FileDialog::UpdatePath()
  405. {
  406.     Collection *col= new OrdCollection;
  407.     Font *rootFont= new_Font(gSysFont->Fid(), gSysFont->Size(),
  408.                     (GrFace)(gSysFont->Face() | eFaceBold));
  409.         
  410.     int n= path.Components();
  411.     if (cPathRoot)
  412.     col->Add(new TextItem(cIdComponent+0, cPathRoot, rootFont, gPoint0));
  413.     for (int i= 1; i < n; i++) {
  414.     col->Add(new TextItem(cIdComponent+i, path(), gSysFont, gPoint0));
  415.     TextItem *ti= new TextItem(cIdNone, cPathSeparator, gSysFont, gPoint0);
  416.     ti->Disable();
  417.     col->Add(ti);
  418.     }
  419.     pathMenu->SetCollection(col);
  420.     pathPopup->SetSelectedItem(cIdComponent+n-1);
  421. }
  422.  
  423. //---- bitmap images for file icons --------------------------------------
  424.  
  425. static u_short DirectoryBits[]= {
  426. #   include "images/directory.im"
  427. };
  428. static u_short FileBits[]= {
  429. #   include "images/file.im"
  430. };
  431. static u_short ExecBits[]= {
  432. #   include "images/exec.im"
  433. };
  434. static u_short AsciiBits[]= {
  435. #   include "images/ascii.im"
  436. };
  437.  
  438. Bitmap *gDirectoryIcon, *gFileIcon, *gExecIcon, *gAsciiIcon;
  439.  
  440. //---- FileItem -----------------------------------------------------------
  441.  
  442. MetaImpl(FileItem, (TP(label), TP(icon), TB(shallow), 0));
  443.  
  444. FileItem::FileItem(char *f, bool s) :
  445.         VObjectPair(icon= new ImageItem(
  446.                     gFileIcon ? gFileIcon
  447.                           : (gFileIcon= new Bitmap(16, FileBits)), 13), 
  448.                 label= new TextItem(f, gSysFont, Point(4,0)))
  449. {
  450.     type= 0;
  451.     shallow= s;
  452. }
  453.  
  454. FileItem::~FileItem()
  455.     SafeDelete(type); 
  456. }
  457.  
  458. bool FileItem::IsDirectory()
  459.     return type && (strcmp(type->Type(), cDocTypeDirectory) == 0); 
  460. }
  461.  
  462. char *FileItem::LookupName()
  463. {
  464.     return Name();
  465. }
  466.  
  467. void FileItem::Draw(Rectangle r)
  468. {
  469.     if (! type) {
  470.     type= gSystem->GetFileType(LookupName(), shallow);
  471.     UpdateIcon();
  472.     }
  473.     VObjectPair::Draw(r); 
  474. }
  475.  
  476. void FileItem::UpdateIcon()
  477. {
  478.     Bitmap *bm= 0;
  479.     
  480.     if (IsDirectory()) {
  481.     if (gDirectoryIcon == 0)
  482.         gDirectoryIcon= new Bitmap(16, DirectoryBits);
  483.     bm= gDirectoryIcon;
  484.     } else if (type->IsExecutable()) {
  485.     if (gExecIcon == 0)
  486.         gExecIcon= new Bitmap(16, ExecBits);
  487.     bm= gExecIcon;
  488.     } else if (type->IsCCode()) {
  489.     if (gAsciiIcon == 0)
  490.         gAsciiIcon= new Bitmap(16, AsciiBits);
  491.     bm= gAsciiIcon;
  492.     }
  493.     if (bm)
  494.     icon->SetBitmap(bm, FALSE);
  495. }
  496.  
  497. char *FileItem::AsString()
  498.     return Name(); 
  499. }
  500.  
  501. //---- OpenFile ----------------------------------------------------------------
  502.  
  503. FILE *OpenFile(const char *name, const char *rw, const char *va_(cp), ...)
  504. {
  505.     const char *path;
  506.     FILE *fp= 0;
  507.     va_list ap;
  508.     va_start(ap,va_(cp));
  509.     
  510.     for (int i= 0; ; i++) {
  511.     if (i == 0)
  512.         path= va_(cp);
  513.     else
  514.         if ((path= va_arg(ap, const char*)) == 0)
  515.         break;
  516.     if (fp= fopen((char*) form("%s/%s", path, name), (char*)rw))
  517.         break;
  518.     }     
  519.     if (fp == 0) {
  520.     FileDialog *fileDialog= new FileDialog;
  521.     if (fileDialog->ShowInWindow(eFDRead, gWindow, 0,
  522.                     form("Please locate %s", name)) == cIdOk)
  523.         fp= fopen((char*) fileDialog->FileName(), (char*)rw);
  524.     }
  525.  
  526.     va_end(ap);
  527.     
  528.     if (fp == 0)
  529.     Fatal("::OpenFile", "can't locate %s", name);
  530.     return fp;
  531. }
  532.